package cn.tedu.gateway.predicate;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import javax.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * 自定义断言工厂类 CheckAutoRoutePredicateFactory,必须以RoutePredicateFactory结尾
 */
@Component//将这个类交给Spring容器管理
public class CheckAutoRoutePredicateFactory extends
        //1. 继承 抽象的路由断言工厂类 AbstractRoutePredicateFactory类，传参传的是 静态的内部类CheckAutoRoutePredicateFactory.Config
        AbstractRoutePredicateFactory<CheckAutoRoutePredicateFactory.Config> {

    /**
     * 3. 创建构造方法,它的作用是：
     * a.当创建CheckAutoRoutePredicateFactory对象时自动执行
     * b.通过super()调用父类AbstractRoutePredicateFactory的构造方法
     * c.告诉父类：我这个断言工厂使用的是CheckAutoRoutePredicateFactory.Config这个配置类
     * 为什么要这么做呢？
     * Spring Cloud Gateway要求所有的路由断言工厂都要：
     * a.继承AbstractRoutePredicateFactory抽象类
     * b.在构造函数中告诉父类使用哪个配置类
     * c.这样父类才知道如何处理配置参数*/
    public CheckAutoRoutePredicateFactory(){
        super(CheckAutoRoutePredicateFactory.Config.class);
    }

    //4.下面这个方法的作用是将Config类中的属性映射到路由断言工厂类CheckAutoRoutePredicateFactory中：
    // 这个方法的作用是定义在 YAML 配置文件中使用这个断言时的快捷字段顺序。它告诉 Spring Cloud Gateway，
    // 当在配置文件中使用 CheckAuto=jack 这样的简写形式时，应该将 "jack" 这个值赋给配置类中的 "name" 字段
    public List<String> shortcutFieldOrder(){
        return Arrays.asList("name");
    }

    /**
     * 5. 创建apply方法，作用是定义断言规则
     * Predicate是什么？ 是Java 8引入的函数式接口 ,专门用于做真假判断 ,只有一个方法：boolean test(T t).
     * ServerWebExchange是什么? Spring WebFlux中的核心对象 , 代表一个HTTP请求-响应的交互过程 , 包含了请求信息和响应信息
     * Predicate<ServerWebExchange> 组合起来的意思就是定义一个判断规则：输入：一个HTTP请求(ServerWebExchange)  输出：true(通过)或false(拒绝)
     * @param config
     * @return */
    @Override
    public Predicate<ServerWebExchange> apply(Config config){
        //new GatewayPredicate() 是创建一个网关断言对象。
        //GatewayPredicate ：Spring Cloud Gateway中的专用断言接口 ，继承自Java的Predicate接口，专门用于网关路由的条件判断
        //为什么要new它？
        // 1.实现判断逻辑：通过重写test方法来定义具体的判断规则 2.返回判断结果：true表示符合条件，false表示不符合
        // 3.集成到网关：让Spring Cloud Gateway知道如何使用这个判断规则
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //这里的逻辑判断较为简单，后续可以通过ServerWebExchange从请求中获取信息进行判断
                if (config.getName().equals("jack"))
                    return true;
                return false;
            }
        };
    }

    //2. 创建静态内部类Config,并声明用于接收属性的参数，提供访问getter和setter方法
    // 可以从application.yml配置文件中读取信息
    @Validated//添加校验注解
    public static class Config{
        @NotEmpty//添加非空校验,原因是name属性不能为空
        public String name;

        public String getName() {
            return name;
        }//getter方法

        public void setName(String name) {
            this.name = name;
        }//setter方法
    }
}

